package com.smh.demo1.a15;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * @author shiminghui
 * @date 2025/4/18 21:43
 * @description: TODO
 */
public class A15_1Application {
    /**
     * 总结:
     * 代理对象创建时会调用findEligibleAdvisors,如果集合为空,则返回原始对象,否则返回代理对象.
     * 这个方法就是遍历Advisors列表,用里面的切点进行匹配,将匹配的Advisor添加到代理对象的Advisors列表中,
     * 当方法调用时,会根据方法寻找对应的Advisor,如果Advisor不是MethodInterceptor类型,则使用适配器继续转化,然后存储到一个
     * map表里面,key是通过method计算出来的,value就是方法对应的methodInterceptor集合
     * 最后创建一个methodInvocation,传入代理对象,切点方法,切点方法参数,切点方法对应的拦截器集合,然后调用proceed方法,
     * 这个方法会调用拦截器的invoke方法,然后调用proceed方法,这个方法会调用拦截器的invoke方法,然后调用proceed方法,直到最后一个拦截器,
     */


    public static void main(String[] args) throws Throwable {

        Target target = new Target();
        MyMethodInvocation myMethodInvocation = new MyMethodInvocation(target, Target.class.getMethod("foo"), new Object[0], new ArrayList<>() {{
            add(new MyMethodInterceptor1());
            add(new MyMethodInterceptor2());
        }});
        myMethodInvocation.proceed();

    }

    static class Target {
        public void foo() {
            System.out.println("foo");
        }
    }

    static class MyMethodInterceptor1 implements MethodInterceptor {

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("before1");
            Object o = invocation.proceed();
            System.out.println("after1");
            return 0;
        }
    }

    static class MyMethodInterceptor2 implements MethodInterceptor {

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("before2");
            Object o = invocation.proceed();
            System.out.println("after2");
            return 0;
        }
    }

    static class MyMethodInvocation implements MethodInvocation {

        private Target target;
        private Method method;
        private Object[] args;

        private ArrayList<MethodInterceptor> interceptors;

        private int index = 0;

        public MyMethodInvocation(Target target, Method method, Object[] args, ArrayList<MethodInterceptor> interceptors) {
            this.target = target;
            this.method = method;
            this.args = args;
            this.interceptors = interceptors;
        }


        @Override
        public Method getMethod() {
            return method;
        }

        @Override
        public Object[] getArguments() {
            return args;
        }

        @Override
        public Object proceed() throws Throwable {
            if (index >= interceptors.size()) {
                return method.invoke(target, args);
            }
            Object invoke = interceptors.get(index++).invoke(this);
            return invoke;
        }

        @Override
        public Object getThis() {
            return target;
        }

        @Override
        public AccessibleObject getStaticPart() {
            return method;
        }
    }


}
